package com.ztr.conversion.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.InputStream;
import java.nio.charset.Charset;

/**
 * <p>
 * 文件工具类
 * </p>
 */
@Slf4j
public class MyFileUtil {


    /**
     * 将指定源路径下的文件或目录打包成ZIP格式的压缩文件。
     *
     * @param srcPath        源文件或目录的路径。这是要被打包的文件或目录的路径。
     * @param zipPath        打包后ZIP文件的路径。指定打包后生成的ZIP文件的保存路径和名称。
     * @param isWithSrcDir   是否包含源目录。如果为true，则打包时会包含源目录结构；如果为false，则只打包源目录下的文件，不包含目录本身。
     * @param isDeleteSrcZip 是否删除源文件或目录。如果为true，则在打包完成后删除源文件或目录；如果为false，则保留源文件或目录。
     * @return 返回打包后的ZIP文件。返回打包操作生成的ZIP文件对象。
     */
    public static File zip(String srcPath, String zipPath, boolean isWithSrcDir, boolean isDeleteSrcZip) {
        // 输出调试信息，记录压缩文件操作的源路径和目标路径
        log.debug("【压缩文件】 源目录路径: 【{}】 打包后的路径+文件后缀名: 【{}】", srcPath, zipPath);

        // 调用ZipUtil类的zip方法进行文件或目录的打包操作
        File zipFile = ZipUtil.zip(srcPath, zipPath, isWithSrcDir);

        // 如果参数指定需要删除源文件或目录，则执行删除操作
        // 删除目录 -> 保证下次生成文件的时候不会累计上次留下的文件
        if (isDeleteSrcZip) {
            MyFileUtil.deleteFileOrFolder(srcPath);
        }

        // 返回打包后的ZIP文件对象
        return zipFile;
    }


    /**
     * 删除指定路径的文件或文件夹。
     *
     * @param fullFileOrDirPath 要删除的文件或文件夹的完整路径。路径可以是相对路径或绝对路径。
     * @return 如果删除成功，则返回true；如果删除失败，例如由于权限不足或路径不存在，则返回false。
     * @see FileUtil#del(String) 有关FileUtil.del方法的更多详细信息，请参阅FileUtil类的del方法文档。
     */
    public static boolean deleteFileOrFolder(String fullFileOrDirPath) {
        return FileUtil.del(fullFileOrDirPath);
    }


    /**
     * 创建或更新一个文件。
     * 如果指定的文件不存在，则创建一个新的空文件。如果文件已存在，则不做任何修改，但仍然返回该文件对象。
     * 这个方法的主要作用是确保给定路径的文件存在，或者创建一个新的文件以便后续操作。
     *
     * @param fullFilePath 文件的完整路径，包括文件名和扩展名。
     * @return 返回创建或已存在的文件对象。
     */
    public static File touch(String fullFilePath) {
        return FileUtil.touch(fullFilePath);
    }


    /**
     * 从输入流中解压ZIP文件到指定目录。
     * 此方法将输入流中的ZIP数据写入临时文件，然后解压该临时文件到指定的输出目录。
     * 解压完成后，可以选择删除原始ZIP文件。
     *
     * @param inputStream ZIP文件的输入流。
     * @param zipFilePath ZIP文件的路径，用于创建临时文件。
     * @param outFileDir  解压后的文件输出目录。
     * @param isDeleteZip 是否删除原始ZIP文件的标志。
     * @return 解压后的文件目录。
     * @throws Exception 如果解压或文件操作失败，抛出异常。
     */
    @SneakyThrows(Exception.class)
    public static File unzip(InputStream inputStream, String zipFilePath, String outFileDir, boolean isDeleteZip) {
        // 记录解压任务开始信息
        log.debug("【解压文件】 zip文件路径: 【{}】 解压后的目录路径: 【{}】", zipFilePath, outFileDir);

        // 从输入流创建一个临时ZIP文件
        // zip压缩文件
        File zipFile = FileUtil.newFile(zipFilePath);
        // 将输入流中的ZIP数据写入临时文件
        // 写入文件
        FileUtils.copyInputStreamToFile(inputStream, zipFile);

        // 使用指定编码（GBK）解压ZIP文件到指定目录
        // 编码方式 "UTF-8" 、"GBK" 【注： gbk编码才能解决报错: java.lang.IllegalArgumentException: MALFORMED】
        File outFile = ZipUtil.unzip(zipFilePath, outFileDir, Charset.forName("GBK"));

        // 如果指定，删除临时ZIP文件
        // 删除zip -> 保证下次解压后的文件数据不会累计上次解压留下的文件
        if (isDeleteZip) {
            MyFileUtil.deleteFileOrFolder(zipFilePath);
        }

        // 返回解压后的文件目录
        return outFile;
    }


    /**
     * 读取文件的内容。
     * <p>
     * 该方法通过调用FileUtil类的readUtf8String方法，以UTF-8编码读取指定文件的内容，并将内容作为字符串返回。
     * 如果文件不存在或无法读取，此方法可能抛出异常。
     *
     * @param file 要读取内容的文件对象。
     * @return 文件的内容作为字符串返回。
     */
    public static String readFileContent(File file) {
        return FileUtil.readUtf8String(file);
    }


    /**
     * 读取指定文件的全部内容。
     * <p>
     * 本方法封装了文件读取的逻辑，以便更方便地获取文件的UTF-8编码文本内容。
     * 使用者无需关心文件的读取细节，只需提供文件路径即可。
     *
     * @param filePath 文件的路径，可以是相对路径或绝对路径。
     *                 路径格式应与文件系统支持的格式相符。
     * @return 文件的UTF-8编码文本内容。如果文件不存在或读取失败，返回null。
     */
    public static String readFileContent(String filePath) {
        return FileUtil.readUtf8String(filePath);
    }


    /**
     * 读取指定文件路径的文件内容，并将其以字节数组的形式返回。
     * <p>
     * 此方法封装了文件读取的逻辑，通过调用FileUtil类的readBytes方法来实现。
     * 它提供了一个简单的接口，用于从文件系统中按字节读取文件内容，
     * 而不需要直接处理文件流，简化了文件读取的操作。
     *
     * @param filePath 文件的路径，可以是相对路径或绝对路径。路径应指向一个存在的文件。
     * @return 返回一个字节数组，数组中的每个元素代表文件中对应位置的一个字节。
     * 如果文件不存在或读取发生错误，则可能返回null。
     */
    public static byte[] readBytes(String filePath) {
        return FileUtil.readBytes(filePath);
    }


    /**
     * 将字符串内容写入指定路径的文件中。
     * <p>
     * 该方法通过调用FileUtil类的writeUtf8String方法，将给定的字符串内容以UTF-8格式写入到指定路径的文件中。
     * 主要用于简化文件内容写入的操作，隐藏了具体的文件操作细节。
     *
     * @param fileContent 要写入文件的字符串内容。
     * @param filePath    文件的路径，包括文件名和扩展名。
     * @return 返回写入内容后的文件对象。
     * @throws Exception 如果写入过程中发生任何异常，例如文件权限问题或磁盘空间不足等，会抛出异常。
     */
    @SneakyThrows(Exception.class)
    public static File writeFileContent(String fileContent, String filePath) {
        return FileUtil.writeUtf8String(fileContent, filePath);
    }


    /**
     * 将字节数据写入指定文件。
     * <p>
     * 该方法通过调用FileUtil的writeBytes方法，将给定的字节数据写入指定路径的文件中。
     * 主要用于处理需要将字节数组形式的数据写入文件的场景。
     *
     * @param data     要写入文件的字节数据。
     * @param filePath 目标文件的路径。
     * @return 写入数据后的文件对象。
     * @throws Exception 如果写入过程中发生错误，会抛出异常。
     */
    @SneakyThrows(Exception.class)
    public static File writeFileContent(byte[] data, String filePath) {
        return FileUtil.writeBytes(data, filePath);
    }

    /**
     * 程序入口主方法。
     * 主要功能是解压指定的zip文件并读取其中某个文件的内容。
     *
     * @param args 命令行参数，未使用
     */
    public static void main(String[] args) {
        try {
            // 指定待解压的zip文件路径
            String filePath = "E:\\IT_zhengqing\\code\\me-workspace\\最新代码生成器\\code-api\\document\\import\\blog.zip";
            // 指定解压后的文件输出目录
            String filePathX = "E:\\IT_zhengqing\\code\\me-workspace\\最新代码生成器\\code-api\\document\\import";
            // 调用解压方法，返回解压后的文件或目录
            // File file =
            // FileUtil.newFile(filePath);
            // InputStream fileInputStream = new FileInputStream(file);
            File unzip = ZipUtil.unzip(filePath, filePathX);
            // 输出解压后的文件或目录路径
            System.out.println(unzip);

            // 读取指定文件的内容，文件路径为解压后的文件之一
            String fileContent = FileUtil.readUtf8String(filePath);
        } catch (Exception e) {
            // 捕获并打印异常信息
            e.printStackTrace();
        }

    }


}
